#include "command.h"

CommandHandler::CommandHandler()
{
    // 初始化当前目录为进程当前工作目录
    char cwd[1024];
    if (getcwd(cwd, sizeof(cwd)))
    {
        current_dir_ = cwd;
    }
    else
    {
        current_dir_ = "/";
    }

    Logger::info("CommandHandler initialized with current_dir: " + current_dir_);

    // 注册命令处理器
    handlers_["LIST"] = [this](auto &&args)
    { return handle_list(args); };
    handlers_["LS"] = [this](auto &&args)
    { return handle_list(args); };
    handlers_["PWD"] = [this](auto &&args)
    { return handle_pwd(args); };
    handlers_["CWD"] = [this](auto &&args)
    { return handle_cd(args); };
    handlers_["CD"] = [this](auto &&args)
    { return handle_cd(args); };
    handlers_["MKD"] = [this](auto &&args)
    { return handle_mkdir(args); };
    handlers_["MKDIR"] = [this](auto &&args)
    { return handle_mkdir(args); };
    handlers_["RMD"] = [this](auto &&args)
    { return handle_rmdir(args); };
    handlers_["RMDIR"] = [this](auto &&args)
    { return handle_rmdir(args); };
    handlers_["DELE"] = [this](auto &&args)
    { return handle_delete(args); };
    handlers_["DELETE"] = [this](auto &&args)
    { return handle_delete(args); };
    handlers_["HELP"] = [this](auto &&args)
    { return handle_help(args); };
    handlers_["?"] = [this](auto &&args)
    { return handle_help(args); };
    handlers_["STAT"] = [this](auto &&args)
    { return handle_stat(args); };
    handlers_["UPLOAD"] = [this](auto &&args)
    { return handle_upload(args); };
    handlers_["DOWNLOAD"] = [this](auto &&args)
    { return handle_download(args); };
}

CommandHandler::~CommandHandler()
{
    Logger::info("CommandHandler destroyed");
}

void CommandHandler::set_current_dir(const std::string &dir)
{
    std::lock_guard<std::mutex> lock(mutex_);
    current_dir_ = dir;
}

std::string CommandHandler::get_current_dir() const
{
    std::lock_guard<std::mutex> lock(mutex_);
    return current_dir_;
}

std::string CommandHandler::get_absolute_path(const std::string &path) const
{
    if (path.empty())
    {
        return current_dir_;
    }

    // 处理绝对路径
    if (path[0] == '/')
    {
        return path;
    }

    // 处理相对路径
    return current_dir_ + "/" + path;
}

std::string CommandHandler::process(const std::string &command)
{
    // 分割命令和参数
    std::istringstream iss(command);
    std::string cmd;
    std::vector<std::string> args;
    iss >> cmd;

    std::string arg;
    while (iss >> arg)
    {
        args.push_back(arg);
    }

    // 转换为大写
    for (char &c : cmd)
    {
        c = std::toupper(c);
    }

    // 查找处理函数
    auto it = handlers_.find(cmd);
    if (it == handlers_.end())
    {
        return "500 Unknown command: " + cmd;
    }

    try
    {
        return it->second(args);
    }
    catch (const std::exception &e)
    {
        Logger::error("Command error: " + command + " - " + e.what());
        return "500 Command execution error: " + std::string(e.what());
    }
}

std::string CommandHandler::handle_list(const std::vector<std::string> &args)
{
    std::string path = current_dir_;
    if (!args.empty())
    {
        path = get_absolute_path(args[0]);
    }

    Logger::info("Listing directory: " + path);

    std::string listing = get_directory_listing(path);
    if (listing.empty())
    {
        return "550 Failed to list directory: " + path;
    }

    return "200 OK\r\n" + listing;
}

std::string CommandHandler::handle_pwd(const std::vector<std::string> &)
{
    return "257 \"" + current_dir_ + "\" is current directory";
}

std::string CommandHandler::handle_cd(const std::vector<std::string> &args)
{
    if (args.empty())
    {
        return "501 Missing directory argument";
    }

    std::string new_dir = get_absolute_path(args[0]);

    if (chdir(new_dir.c_str()))
    {
        return "550 Cannot change directory to: " + new_dir + " - " + strerror(errno);
    }

    // 更新当前目录
    char cwd[1024];
    if (getcwd(cwd, sizeof(cwd)))
    {
        set_current_dir(cwd);
        return "250 Directory changed to \"" + current_dir_ + "\"";
    }
    return "200 Directory changed";
}

std::string CommandHandler::handle_mkdir(const std::vector<std::string> &args)
{
    if (args.empty())
    {
        return "501 Missing directory argument";
    }

    std::string dir_path = get_absolute_path(args[0]);

    if (mkdir(dir_path.c_str(), 0755))
    {
        return "550 Cannot create directory: " + dir_path + " - " + strerror(errno);
    }

    return "257 \"" + dir_path + "\" directory created";
}

std::string CommandHandler::handle_rmdir(const std::vector<std::string> &args)
{
    if (args.empty())
    {
        return "501 Missing directory argument";
    }

    std::string dir_path = get_absolute_path(args[0]);

    if (rmdir(dir_path.c_str()))
    {
        return "550 Cannot remove directory: " + dir_path + " - " + strerror(errno);
    }

    return "250 \"" + dir_path + "\" directory removed";
}

std::string CommandHandler::handle_delete(const std::vector<std::string> &args)
{
    if (args.empty())
    {
        return "501 Missing file argument";
    }

    std::string file_path = get_absolute_path(args[0]);

    if (unlink(file_path.c_str()))
    {
        return "550 Cannot delete file: " + file_path + " - " + strerror(errno);
    }

    return "250 \"" + file_path + "\" file deleted";
}

std::string CommandHandler::handle_stat(const std::vector<std::string> &args)
{
    if (args.empty())
    {
        return "211 System status OK";
    }

    std::string path = get_absolute_path(args[0]);
    struct stat st;
    if (stat(path.c_str(), &st))
    {
        return "550 Cannot stat: " + path + " - " + strerror(errno);
    }

    std::ostringstream oss;
    oss << "213 File status:\n";
    oss << "  File: " << path << "\n";
    oss << "  Size: " << st.st_size << " bytes\n";
    oss << "  Permissions: " << std::oct << (st.st_mode & 07777) << "\n";

    char time_buf[80];
    strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", localtime(&st.st_mtime));
    oss << "  Modified: " << time_buf << "\n";

    return oss.str();
}

std::string CommandHandler::handle_help(const std::vector<std::string> &)
{
    return "214-The following commands are recognized:\n"
           " USER    PASS    ACCT    CWD     CDUP    SMNT    QUIT    REIN\n"
           " PORT    PASV    TYPE    STRU    MODE    RETR    STOR    STOU\n"
           " APPE    ALLO    REST    RNFR    RNTO    ABOR    DELE    RMD\n"
           " MKD     PWD     LIST    NLST    SITE    SYST    STAT    HELP\n"
           " NOOP    UPLOAD  DOWNLOAD\n"
           "214 Help OK";
}

std::string CommandHandler::handle_upload(const std::vector<std::string> &args)
{
    if (args.size() < 2)
    {
        return "501 Missing arguments for UPLOAD command";
    }
    return "150 Ready to receive file: " + get_absolute_path(args[1]);
}

std::string CommandHandler::handle_download(const std::vector<std::string> &args)
{
    if (args.size() < 2)
    {
        return "501 Missing arguments for DOWNLOAD command";
    }

    std::string file_path = get_absolute_path(args[0]);
    struct stat st;
    if (stat(file_path.c_str(), &st))
    {
        return "550 File not found: " + file_path;
    }

    std::ostringstream oss;
    oss << "150 Opening BINARY mode data connection for " << file_path
        << " (" << st.st_size << " bytes)";
    return oss.str();
}

std::string CommandHandler::get_directory_listing(const std::string &path)
{
    DIR *dir = opendir(path.c_str());
    if (!dir)
    {
        Logger::error("Cannot open directory: " + path + " - " + strerror(errno));
        return "";
    }

    std::ostringstream oss;
    dirent *entry;

    // 添加标题行
    oss << "total " << get_dir_size(path) << "\r\n";

    while ((entry = readdir(dir)) != nullptr)
    {
        // 跳过 "." 和 ".."
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
        {
            continue;
        }

        std::string full_path = path + "/" + entry->d_name;
        struct stat st;
        if (stat(full_path.c_str(), &st))
        {
            continue;
        }

        // 文件类型
        char type;
        if (S_ISDIR(st.st_mode))
            type = 'd';
        else if (S_ISLNK(st.st_mode))
            type = 'l';
        else if (S_ISREG(st.st_mode))
            type = '-';
        else if (S_ISCHR(st.st_mode))
            type = 'c';
        else if (S_ISBLK(st.st_mode))
            type = 'b';
        else if (S_ISFIFO(st.st_mode))
            type = 'p';
        else if (S_ISSOCK(st.st_mode))
            type = 's';
        else
            type = '?';

        // 权限
        char perm[10] = "---------";
        if (st.st_mode & S_IRUSR)
            perm[0] = 'r';
        if (st.st_mode & S_IWUSR)
            perm[1] = 'w';
        if (st.st_mode & S_IXUSR)
            perm[2] = 'x';
        if (st.st_mode & S_IRGRP)
            perm[3] = 'r';
        if (st.st_mode & S_IWGRP)
            perm[4] = 'w';
        if (st.st_mode & S_IXGRP)
            perm[5] = 'x';
        if (st.st_mode & S_IROTH)
            perm[6] = 'r';
        if (st.st_mode & S_IWOTH)
            perm[7] = 'w';
        if (st.st_mode & S_IXOTH)
            perm[8] = 'x';

        // 用户和组
        struct passwd *pwd = getpwuid(st.st_uid);
        struct group *grp = getgrgid(st.st_gid);
        const char *user = pwd ? pwd->pw_name : "unknown";
        const char *group = grp ? grp->gr_name : "unknown";

        // 时间
        char time_buf[80];
        strftime(time_buf, sizeof(time_buf), "%b %d %H:%M", localtime(&st.st_mtime));

        oss << type << perm << " "
            << std::setw(3) << st.st_nlink << " "
            << std::setw(8) << user << " "
            << std::setw(8) << group << " "
            << std::setw(10) << st.st_size << " "
            << time_buf << " "
            << entry->d_name << "\r\n";
    }
    closedir(dir);
    return oss.str();
}

long CommandHandler::get_dir_size(const std::string &path) const
{
    long total = 0;
    DIR *dir = opendir(path.c_str());
    if (!dir)
        return 0;

    dirent *entry;
    while ((entry = readdir(dir)) != nullptr)
    {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
        {
            continue;
        }

        std::string full_path = path + "/" + entry->d_name;
        struct stat st;
        if (stat(full_path.c_str(), &st) == 0)
        {
            if (S_ISDIR(st.st_mode))
            {
                total += get_dir_size(full_path);
            }
            else
            {
                total += st.st_blocks * 512; // 块大小
            }
        }
    }
    closedir(dir);
    return total / 1024; // 返回 KB 单位
}